#include "extendedsdcparser.h"

void ExtendedSdcParser::clearDriverInfo(std::string driver_name)
{
        //  (*this).inputDrivers[driver_name].cap = 0.0;
}

void ExtendedSdcParser::readSdcFile ()
{
        bool valid;
        //read clock info
        (*this).read_clock(this->clk_info.clockName, 
                           this->clk_info.clockPort, this->clk_info.period);
        
        //read input delay
        do {
                string portName ;
                double delay ;
                
                valid = (*this).read_input_delay (portName, delay) ;
                
                if (valid)
                {
                        this->inputDelays[portName] = delay;
                        //cout << "Input port " << portName << " has delay " << delay << endl ;
                }
        } while (valid) ;
        
        //read driver info
        do {
                string portName ;
                string driverSize ;
                string driverPin ;
                double inputTransitionFall ;
                double inputTransitionRise ;
                
                valid = (*this).read_driver_info (portName, driverSize, driverPin,
                                                  inputTransitionFall, inputTransitionRise) ;

                if (valid) {
                        DriverInfo DI;
						
                        DI.driverSize = driverSize;
                        DI.dirverPin = driverPin;
                        DI.inputTransFall = inputTransitionFall;
                        DI.inputTransRise = inputTransitionRise;
                        // DI.maxCap = 0.0;
                        //DI.cap = 0.0;
                        
                        this->inputDrivers[portName] = DI;
                        //cout << "Input port " << portName << " is assumed to be connected to the "
                        //<< driverPin << " pin of lib cell " << driverSize << endl ;
                        //cout << "This virtual driver is assumed to have input transitions: "
                        //<< inputTransitionFall << " (fall) and " << inputTransitionRise
                        //<< " (rise)" << endl ;
                }
    
    
        } while (valid) ;

        //read output delay
        do {
                string portName ;
                double delay ;

                valid = (*this).read_output_delay (portName, delay) ;

                if (valid)
                {
                        this->outputDelays[portName] = delay;
                        //cout << "Output port " << portName << " has delay " << delay << endl ;
                }
                
        } while (valid) ;

        //read output load
        do {
                string portName ;
                double load ;

                valid = (*this).read_output_load (portName, load) ;

                if (valid)
                {
                        this->outputLoads[portName] = load;
                        //cout << "Output port " << portName << " has load " << load << endl ;
                }
        } while (valid) ;

}

void ExtendedSdcParser::updateOutputCap (CircuitGraph& graphIn)
{       
        boost::graph_traits<CircuitGraph>::vertex_iterator vi, vi_end ;
        
        for (boost::tie(vi, vi_end) = boost::vertices(graphIn); vi != vi_end ; ++vi)
        {
                if( graphIn[(*vi)].gateType == PrimaryOutput)
                        graphIn[(*vi)].outCapacitance = this->outputLoads[graphIn[(*vi)].instanceName] ;
        }
}

void ExtendedSdcParser::readOutputLoads ()
{

        bool valid ;
        do {
                string portName ;
                double load ;

                valid = this->read_output_load (portName, load) ;

                if (valid)
                        this->outputLoads[portName] = load ;

        } while (valid) ;
}

void ExtendedSdcParser::readInputDelays ()
{
        bool valid ;
        do {
                string portName ;
                double delay ;

                valid = this->read_input_delay (portName, delay) ;

                if (valid)
                        this->inputDelays[portName] = delay ;

        } while (valid) ;
}

void ExtendedSdcParser::readInputDrivers ()
{

        bool valid ;
        
        do {

                
                string portName ;
                string driverSize ;
                string driverPin ;
                double inputTransitionFall ;
                double inputTransitionRise ;
                
                valid = this->read_driver_info (portName, driverSize, driverPin,
                                                inputTransitionFall, inputTransitionRise) ;
                
                if (valid) {
                        DriverInfo tmpDriver ;
                        tmpDriver.driverSize = driverSize ;
                        tmpDriver.dirverPin = driverPin ;
                        tmpDriver.inputTransFall = inputTransitionFall ;
                        tmpDriver.inputTransRise = inputTransitionRise ;
                        this->inputDrivers[portName] = tmpDriver ;
                }
        } while (valid) ;
}

void ExtendedSdcParser::readOutputDelays ()
{
        bool valid ;
        do {
                string portName ;
                double delay ;

                valid = this->read_output_delay (portName, delay) ;

                if (valid)
                        this->outputDelays[portName] = delay ;

        } while (valid) ;
}

void ExtendedSdcParser::updateSequentialTime(CircuitGraph& graphIn, ExtendedLibParser& library)
{
        boost::graph_traits<CircuitGraph>::vertex_iterator vi, vi_end ;
        
        std::map<std::string, double> inputFallTrans, inputRiseTrans ;
        
        for (boost::tie(vi, vi_end) = boost::vertices(graphIn); vi != vi_end; ++vi)
        {
                if ( graphIn[(*vi)].gateType == Sequential)
                {
                        double outCap = graphIn.calculateTotalOutputCap((*vi), library) ;
                        
                        inputFallTrans["ck"] = 5.0 ;
                        inputRiseTrans["ck"] = 5.0 ;
                        bool valid ;
                        double outputRiseTrans = library.maxRiseTransition(graphIn[(*vi)].cellName, inputRiseTrans, outCap, valid) ;
                        double outputFallTrans = library.maxFallTransition(graphIn[(*vi)].cellName, inputFallTrans, outCap, valid) ;
                        
                        double riseArrivalTime = library.maxRiseDelay(graphIn[(*vi)].cellName, inputRiseTrans, outCap, valid);
                        double fallArrivalTime = library.maxFallDelay(graphIn[(*vi)].cellName, inputFallTrans, outCap, valid);
                        
                        graphIn[(*vi)].arrivalTime = std::make_pair( riseArrivalTime, fallArrivalTime ) ;
                        graphIn[(*vi)].slewTime = std::make_pair( outputRiseTrans, outputFallTrans ) ;

                }
        }
}

void ExtendedSdcParser::updateInputTime(CircuitGraph& graphIn, ExtendedLibParser& library)
{
        boost::graph_traits<CircuitGraph>::vertex_iterator vi, vi_end ;
        
        for (boost::tie(vi, vi_end) = boost::vertices(graphIn); vi != vi_end ; ++vi)
        {
                if( graphIn[(*vi)].gateType == Input)
                {
                
                        // Find output capacitance                                                                                                                                                   
                        double outCap = graphIn.calculateTotalOutputCap((*vi), library) ;
                        
                        // Find the load independent arrival time                                                                                                                                    
                        double loadIndepArrivalTime = this->inputDelays[ graphIn[(*vi)].instanceName ] ;
                        
                        
                        // Find the load dependent arrival time                                                                                                                                      
                        std::string drivingName = this->inputDrivers[ graphIn[(*vi)].instanceName ].driverSize ;
                        
                        std::map<std::string, double> inputFallTrans ;
                        std::map<std::string, double> inputRiseTrans ;
                        
                        inputFallTrans["a"] = this->inputDrivers[ graphIn[(*vi)].instanceName ].inputTransFall ;
                        inputRiseTrans["a"] = this->inputDrivers[ graphIn[(*vi)].instanceName ].inputTransRise ;
                        
                        bool valid ;
                        double incrRiseArrivalTime = library.maxFallDelay(drivingName, inputFallTrans,outCap, valid) 
                                - library.maxFallDelay(drivingName, inputFallTrans,0.0, valid) ;
                                                                                        
                        double incrFallArrivalTime = library.maxRiseDelay(drivingName, inputRiseTrans, outCap, valid) 
                                - library.maxRiseDelay(drivingName, inputRiseTrans,0.0, valid);
                        
                        graphIn[(*vi)].arrivalTime = std::make_pair(incrFallArrivalTime + loadIndepArrivalTime , 
                                                                    incrRiseArrivalTime + loadIndepArrivalTime) ;
                                                                                                                        
                        double outputFallTrans = library.maxRiseTransition(drivingName, inputRiseTrans, outCap, valid) ;
                        double outputRiseTrans = library.maxFallTransition(drivingName, inputFallTrans, outCap, valid) ;
                        
                        graphIn[(*vi)].slewTime = std::make_pair(outputFallTrans, outputRiseTrans) ;
                        
                }
        }

}
